﻿(function(window, factory) {
	var getContext = {
		initNew: factory
	};

	if (typeof define === "function" && define.amd) {
		define(function () {
			return getContext;
		});
	} else if (typeof exports === "object") {
		module.exports = function () {
			return getContext;
		};
	} else {
		window.echoChangeByCc = getContext;
	}
})(window, function(config) {
	"use strict";
	var echo = {};
	var callback = function() {};
	var offset, poll, delay, useDebounce, unload, container, scrollListenElement;
	var isHidden = function(element) {
		return element.offsetParent === null;
	};
	var inView = function(element, view) {
		if (isHidden(element)) {
			return false;
		}
		var box = element.getBoundingClientRect();
		return box.right >= view.l && box.bottom >= view.t && box.left <= view.r && box.top <= view.b;
	};
	var debounceOrThrottle = function() {
		if (!useDebounce && !!poll) {
			return;
		}
		clearTimeout(poll);
		poll = setTimeout(function() {
			echo.render();
			poll = null;
		}, delay);
	};

	function init(opts) {
		opts = opts || {};
		var offsetAll = opts.offset || 0;
		var offsetVertical = opts.offsetVertical || offsetAll;
		var offsetHorizontal = opts.offsetHorizontal || offsetAll;
		var optionToInt = function(opt, fallback) {
			return parseInt(opt || fallback, 10);
		};
		container = opts.container || document.body;
		scrollListenElement = container !== document.body ? container : window;
		offset = {
			t: optionToInt(opts.offsetTop, offsetVertical),
			b: optionToInt(opts.offsetBottom, offsetVertical),
			l: optionToInt(opts.offsetLeft, offsetHorizontal),
			r: optionToInt(opts.offsetRight, offsetHorizontal)
		};
		delay = optionToInt(opts.throttle, 250);
		useDebounce = opts.debounce !== false;
		unload = !!opts.unload;
		callback = opts.callback || callback;
		echo.render();
		if (document.addEventListener) {
			scrollListenElement.addEventListener("scroll", debounceOrThrottle, false);
			scrollListenElement.addEventListener("load", debounceOrThrottle, false);
		} else {
			scrollListenElement.attachEvent("onscroll", debounceOrThrottle);
			scrollListenElement.attachEvent("onload", debounceOrThrottle);
		}
	}
	echo.render = function() {
		var nodes = container.querySelectorAll("img[data-echo], [data-echo-background]");
		var length = nodes.length;
		var src, elem;
		var view = {
			l: 0 - offset.l,
			t: 0 - offset.t,
			b: container.clientHeight + offset.b,
			r: container.clientWidth + offset.r
		};
		for (var i = 0; i < length; i++) {
			elem = nodes[i];
			if (inView(elem, view)) {
				if (unload) {
					elem.setAttribute("data-echo-placeholder", elem.src);
				}
				if (elem.getAttribute("data-echo-background") !== null) {
					elem.style.backgroundImage = "url(" + elem.getAttribute("data-echo-background") + ")";
				} else {
					elem.src = elem.getAttribute("data-echo");
				}
				if (!unload) {
					elem.removeAttribute("data-echo");
					elem.removeAttribute("data-echo-background");
				}
				callback(elem, "load");
			} else if (unload && !!(src = elem.getAttribute("data-echo-placeholder"))) {
				if (elem.getAttribute("data-echo-background") !== null) {
					elem.style.backgroundImage = "url(" + src + ")";
				} else {
					elem.src = src;
				}
				elem.removeAttribute("data-echo-placeholder");
				callback(elem, "unload");
			}
		}
		if (!length) {
			echo.detach();
		}
	};
	echo.detach = function() {
		if (document.removeEventListener) {
			scrollListenElement.removeEventListener("scroll", debounceOrThrottle);
		} else {
			scrollListenElement.detachEvent("onscroll", debounceOrThrottle);
		}
		clearTimeout(poll);
	};

	init(config);

	return echo;
});